﻿using Aeon.Emulator.Dos.Programs;
using Aeon.Emulator.Dos.VirtualFileSystem;

namespace Aeon.Emulator.Dos
{
    /// <summary>
    /// Contains information about a DOS process.
    /// </summary>
    public sealed class DosProcess
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the DosProcess class.
        /// </summary>
        /// <param name="image">Image process was loaded from.</param>
        /// <param name="pspSegment">Segment of the process's PSP.</param>
        /// <param name="environmentSegment">Segment of the process's environment block.</param>
        /// <param name="commandLineArgs">Command line arguments used to launch the process.</param>
        internal DosProcess(ProgramImage image, ushort pspSegment, ushort environmentSegment, string commandLineArgs)
        {
            if(image != null)
            {
                this.fullPath = image.FullPath;
                this.imageName = image.FileName;
            }
            else
            {
                this.fullPath = VirtualPath.RelativeCurrent;
                this.imageName = string.Empty;
            }
            this.pspSegment = pspSegment;
            this.environmentSegment = environmentSegment;
            this.commandLineArgs = commandLineArgs;

            // These get initialized to the command line data area.
            this.DiskTransferAreaSegment = pspSegment;
            this.DiskTransferAreaOffset = 0x80;
        }
        /// <summary>
        /// Initializes a new instance of the DosProcess class.
        /// </summary>
        /// <param name="fullPath">Full path to the image that started the process.</param>
        /// <param name="imageName">Image process was loaded from.</param>
        /// <param name="pspSegment">Segment of the process's PSP.</param>
        /// <param name="environmentSegment">Segment of the process's environment block.</param>
        /// <param name="commandLineArgs">Command line arguments used to launch the process.</param>
        private DosProcess(VirtualPath fullPath, string imageName, ushort pspSegment, ushort environmentSegment, string commandLineArgs)
        {
            this.fullPath = fullPath;
            this.imageName = imageName;
            this.pspSegment = pspSegment;
            this.environmentSegment = environmentSegment;
            this.commandLineArgs = commandLineArgs;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the full path to the image that was loaded.
        /// </summary>
        public VirtualPath FullPath
        {
            get { return fullPath; }
        }
        /// <summary>
        /// Gets the name of the process.
        /// </summary>
        public string ImageName
        {
            get { return imageName; }
        }
        /// <summary>
        /// Gets a string containing the arguments used to launch the process.
        /// </summary>
        public string CommandLineArguments
        {
            get { return commandLineArgs; }
        }
        #endregion

        #region Internal Properties
        /// <summary>
        /// Gets the segment of the process's PSP.
        /// </summary>
        internal ushort PrefixSegment
        {
            get { return pspSegment; }
        }
        /// <summary>
        /// Gets the segment of the process's environment block.
        /// </summary>
        internal ushort EnvironmentSegment
        {
            get { return environmentSegment; }
        }
        /// <summary>
        /// Gets or sets the segment of the process disk transfer area.
        /// </summary>
        internal ushort DiskTransferAreaSegment { get; set; }
        /// <summary>
        /// Gets or sets the offset of the process disk transfer area.
        /// </summary>
        internal ushort DiskTransferAreaOffset { get; set; }
        /// <summary>
        /// Gets or sets a buffer containing the processor state before the process is started.
        /// </summary>
        internal byte[] InitialProcessorState { get; set; }
        #endregion

        #region Public Methods
        /// <summary>
        /// Returns a short description of the process.
        /// </summary>
        /// <returns>Short description of the process.</returns>
        public override string ToString()
        {
            return this.ImageName;
        }
        #endregion

        #region Internal Methods
        /// <summary>
        /// Returns a new child process.
        /// </summary>
        /// <param name="pspSegment">PSP segment of the child process.</param>
        /// <returns>New child process.</returns>
        internal DosProcess CreateChildProcess(ushort pspSegment)
        {
            return new DosProcess(this.fullPath, this.imageName, pspSegment, this.environmentSegment, this.commandLineArgs)
            {
                DiskTransferAreaSegment = this.DiskTransferAreaSegment,
                DiskTransferAreaOffset = this.DiskTransferAreaOffset,
            };
        }
        #endregion

        #region Internal Static Fields
        /// <summary>
        /// Temporary process definition used for certain internal allocations.
        /// </summary>
        internal static readonly DosProcess NullProcess = new DosProcess(null, 1, 0, string.Empty);
        #endregion

        #region Private Fields
        private readonly VirtualPath fullPath;
        private readonly string imageName;
        private readonly ushort pspSegment;
        private readonly ushort environmentSegment;
        private readonly string commandLineArgs;
        #endregion
    }
}
